package com.ilxqx.fierce.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.lang.reflect.Method;

/**
 * 动作方法
 *
 * @author Venus
 * @since 1.0.0
 */
@Slf4j
public class ActionMethod {

    private final Object target;

    private final Class<?> targetClass;

    private final Method method;

    private final MethodParameter[] parameters;

    protected ActionMethod(Object target, Class<?> targetClass, Method method) {
        Assert.notNull(target, "Target is required");
        Assert.notNull(targetClass, "TargetClass is required");
        Assert.notNull(method, "Method is required");
        this.target = target;
        this.targetClass = targetClass;
        this.method = method;
        this.parameters = initMethodParameters();
    }


    /**
     * Copy constructor for use in subclasses.
     */
    protected ActionMethod(ActionMethod actionMethod) {
        Assert.notNull(actionMethod, "ActionMethod is required");
        this.target = actionMethod.target;
        this.targetClass = actionMethod.targetClass;
        this.method = actionMethod.method;
        this.parameters = actionMethod.parameters;
    }

    private MethodParameter[] initMethodParameters() {
        int count = this.method.getParameterCount();
        MethodParameter[] result = new MethodParameter[count];
        for (int i = 0; i < count; i++) {
            result[i] = new ActionMethodParameter(this.targetClass, this.method, i);
        }
        return result;
    }

    /**
     * Return the bean for this handler method.
     */
    public Object getTarget() {
        return this.target;
    }

    /**
     * Return the method for this handler method.
     */
    public Method getMethod() {
        return this.method;
    }

    /**
     * This method returns the type of the handler for this handler method.
     * <p>Note that if the bean type is a CGLIB-generated class, the original
     * user-defined class is returned.
     */
    public Class<?> getTargetClass() {
        return this.targetClass;
    }

    /**
     * Return the method parameters for this handler method.
     */
    public MethodParameter[] getMethodParameters() {
        return this.parameters;
    }

    /**
     * Return a short representation of this handler method for log message purposes.
     * @since 4.3
     */
    public String getShortLogMessage() {
        return getTargetClass().getName() + "#" + this.method.getName() +
            "[" + this.method.getParameterCount() + " args]";
    }

    @Override
    public boolean equals(@Nullable Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof ActionMethod)) {
            return false;
        }
        ActionMethod otherMethod = (ActionMethod) other;
        return (this.target.equals(otherMethod.target) && this.method.equals(otherMethod.method));
    }

    @Override
    public int hashCode() {
        return (this.target.hashCode() * 31 + this.method.hashCode());
    }

    @Override
    public String toString() {
        return this.getShortLogMessage();
    }
}
